今天要來改寫昨天的範例程式碼,嘗試透過 Context
撰寫 todoStore.js
放置 todoList 所需的 Data 資料,並透過 mock
模擬整個 todoStore
進行測試,防止報錯及降低元件間的相依性。
步驟一、首先來封裝一個 store
於 store 內傳送 fetchData 資料:
import React, { useContext } from 'react';
import axios from 'axios';
export const TodoDataContext = React.createContext();
export const useTodoStore = () => useContext(TodoDataContext);
export const TodoContextProvider = ({ children }) => {
const fetchData = async () => {
const response = await axios.get(
`https://jsonplaceholder.typicode.com/todos`
);
return response.data;
};
return (
<TodoDataContext.Provider
value={{
fetchData,
}}
>
{children}
</TodoDataContext.Provider>
);
};
步驟二、在 TodoList 的父層級包覆 TodoContextProvider
使 TodoList 能順利取得資料
import React from 'react';
import './App.css';
import TodoList from './components/compos/TodoList';
import axios from 'axios';
import { TodoContextProvider } from './stores/todoStore';
const App = () => {
const fetchData = async () => {
const response = await axios.get(
`https://jsonplaceholder.typicode.com/todos`
);
return response.data;
};
return (
<>
<TodoContextProvider>
<TodoList />
</TodoContextProvider>
</>
);
};
export default App;
步驟三、在 TodoList 內取用 useTodoStore
內的 fetchData
函式,並於 init 時呼叫取得值後傳入
import React, { useEffect, useState } from 'react';
import { useTodoStore } from '@/stores/todoStore';
const TodoList = () => {
const { fetchData } = useTodoStore();
const [todoData, setTodoData] = useState(null);
const init = async () => {
const data = await fetchData();
setTodoData(data);
};
useEffect(() => {
init();
}, []);
return (
<>
<ul>
{todoData &&
todoData.map((item) => <li key={item.id}>{item.title}</li>)}
</ul>
</>
);
};
export default TodoList;
首先來看一下 Jest 文件內 Mock 元件的方法:
'../moduleName'
需要帶入要模擬 module 路徑jest.mock('../moduleName', () => {
return jest.fn(() => 42);
});
// This runs the function specified as second argument to `jest.mock`.
const moduleName = require('../moduleName');
moduleName(); // Will return '42';
接下來來看要怎麼模擬 store 吧?
首先第一個參數路徑的部分要帶入 store 的位置,內層先回傳透過具名匯出的 useTodoStore
,store 內層記得將我們要使用的 fetchData
透過 jest.fn()
進行模擬,並使用 mockReturnValue
回傳設定好的模擬值:
import { render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import TodoList from './TodoList';
jest.mock('@/stores/todoStore', () => ({
useTodoStore: () => ({
fetchData: jest.fn().mockReturnValue([{ id: 'test', title: 'title' }]),
}),
}));
store 模擬完成後,可以開始進行測試了!
測試的部分透過 render
渲染出 TodoList 元件後,透過 waitFor
處理非同步行為,最後斷言設定的 title 模擬值能正確呈現!
test('Test get value from Store', async () => {
render(<TodoList />);
await waitFor(() => {
expect(screen.getByText('title')).toBeInTheDocument();
});
});
運行測試後,可以看見測試的結果:
如果嘗試透過 screen.debug() 也能看到印出後的 DOM 有成功顯示 title !
今天的測試小練習成功,明天也繼續加油吧!
https://jestjs.io/docs/jest-object#jestmockmodulename-factory-options